import tempfile
from pathlib import Path
import os,platform,shutil
from enum import Enum

def renew_file(path:Path):
    try:
        if path.exists():
            if not path.is_dir():
                os.remove(path.resolve())
            else:
                os.removedirs(path.resolve())
    except OSError as e:
        raise OSError("Cannot remove existing file/folder") from e
    # if platform.system()
    path.touch(mode=0o777)

from soj.builtin.environ.common import ensure_file
from typing import ContextManager
class WorkSpace:
    class FileType(Enum):
        INPUT="input",
        OUTPUT="output",
        ANSWER="answer",
        ERROR="error",
        REPORT="report",
        CUSTOM="other"
    def join(self,name:str):
        return os.path.join(self.dir.name,name)
    def join_path(self,name:str):
        return Path(self.join(name)).resolve()
    def __init__(self,create_files=True):
        self.dir=tempfile.TemporaryDirectory()
        self.ready=True
        self.input_file=Path(self.join("input.in"))
        self.output_file=Path(self.join("output.out"))
        self.answer_file=Path(self.join("answer.ans"))
        self.error_file=Path(self.join("stderr.txt"))
        self.report_file=Path(self.join("report.log"))
        if create_files:
            renew_file(self.input_file)
            renew_file(self.output_file)
            renew_file(self.answer_file)
            renew_file(self.error_file)
            renew_file(self.report_file)
    def reprepare_file(self):
        self.input_file=Path(self.join("input.in"))
        self.output_file=Path(self.join("output.out"))
        self.answer_file=Path(self.join("answer.ans"))
        self.error_file=Path(self.join("stderr.txt"))
        self.report_file=Path(self.join("report.log"))
        renew_file(self.input_file)
        renew_file(self.output_file)
        renew_file(self.answer_file)
        renew_file(self.error_file)
        renew_file(self.report_file)
    def import_file(self,type:FileType,source:Path,rename:str|None=None):
        ensure_file(source)
        try:
            if type==self.FileType.INPUT:
                shutil.copyfile(source,self.input_file)
            elif type==self.FileType.OUTPUT:
                shutil.copyfile(source,self.output_file)
            elif type==self.FileType.ERROR:
                shutil.copyfile(source,self.error_file)
            elif type==self.FileType.REPORT:
                shutil.copyfile(source,self.report_file)
            elif type==self.FileType.ANSWER:
                shutil.copyfile(source,self.answer_file)    
            else:
                shutil.copyfile(source,self.join(source.name if rename is None else rename))
        except OSError as e:
            raise OSError(f"File operation error {e}") from e
        except Exception as e:
            raise RuntimeError(f"Unknown error occured in {__file__}")
    def export_file(self,type:FileType,to:Path,filename:Path|None=None):
        if filename is not None:
            filename=filename.resolve().absolute().name
        try:
            if type==self.FileType.INPUT:
                ensure_file(self.input_file)
                shutil.copyfile(self.input_file,to)
            elif type==self.FileType.OUTPUT:
                ensure_file(self.output_file)
                shutil.copyfile(self.output_file,to)
            elif type==self.FileType.ERROR:
                ensure_file(self.error_file)
                shutil.copyfile(self.error_file,to)
            elif type==self.FileType.REPORT:
                ensure_file(self.report_file)
                shutil.copyfile(self.report_file,to)
            elif type==self.FileType.ANSWER:
                ensure_file(self.answer_file)
                shutil.copyfile(self.answer_file,to)    
            else:
                ensure_file(self.join(filename))
                shutil.copyfile(self.join(filename),to)
        except OSError as e:
            raise OSError("File operation error") from e
        except Exception as e:
            raise RuntimeError(f"Unknown error occured in {__file__}")
    def open_handle(self,type:FileType,filename:Path|None=None,mode:str="w+"):
        if filename is not None:
            filename=filename.resolve().absolute().name
        try:
            if type==self.FileType.INPUT:
                ensure_file(self.input_file)
                return open(self.input_file,mode=mode)
            elif type==self.FileType.OUTPUT:
                ensure_file(self.output_file)
                return open(self.output_file,mode=mode)
            elif type==self.FileType.ERROR:
                ensure_file(self.error_file)
                return open(self.error_file,mode=mode)
            elif type==self.FileType.REPORT:
                ensure_file(self.report_file)
                return open(self.report_file,mode=mode)
            elif type==self.FileType.ANSWER:
                ensure_file(self.answer_file)
                return open(self.answer_file,mode=mode)
            else:
                ensure_file(self.join(filename))
                return open(self.join(filename),mode=mode)
        except OSError as e:
            raise OSError("File operation error") from e
        except Exception as e:
            raise RuntimeError(f"Unknown error occured in {__file__}")
    def create_file(self,filename:str):
        path=Path(self.join(filename))
        renew_file(path)
        return path.resolve()
    def write_file(self,filename:str,content:str):
        path=Path(self.join(filename))
        renew_file(path)
        with open(path,"w+",encoding="utf-8") as f:
            f.write(content)
        return path
    def read_file(self,filename:str)->str:
        path=Path(self.join(filename))
        ensure_file(path)
        with open(path,"r",encoding="utf-8") as f:
            return f.read()
    def clear(self):
        if not self.ready:
            return # already cleaned up
        self.ready=False
        self.dir.cleanup()
    def __del__(self):
        self.clear()
    def __enter__(self)->"WorkSpace":
        return self
    def __exit__(self,exc_type,exc_val,exc_tb):
        if exc_type is not None:
            print("Exception occured in WorkSpace")
        self.clear()
        return False